package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageBean;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.dto.QueryDeviceDataDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceDataMapper;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliyunIotProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@Service
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    Client client;
    @Autowired
    AliyunIotProperties aliyunIotProperties;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    DeviceMapper deviceMapper;
    @Autowired
    DeviceDataMapper deviceDataMapper;

    @Override
    @SneakyThrows//帮助方法try catch
    public void syncProductList() {
        QueryProductListRequest request = new QueryProductListRequest();
        request.setCurrentPage(1);
        request.setPageSize(100);

        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());

        QueryProductListResponse response = client.queryProductList(request);
        if (!response.getBody().success) {
            throw new RuntimeException(response.getBody().getErrorMessage());
        }
        List<ProductVo> productVos = BeanUtil.copyToList(response.body.data.list.productInfo, ProductVo.class);
        stringRedisTemplate.opsForValue().set(CacheConstants.IOT_ALL_PRODUCT, JSON.toJSONString(productVos));
    }

    @Override
    public List<ProductVo> allProduct() {
        String s = stringRedisTemplate.opsForValue().get(CacheConstants.IOT_ALL_PRODUCT);
        if (StrUtil.isBlank(s)) {
            return List.of();
        }
        // List<ProductVo> productVos = JSONUtil.toList(s, ProductVo.class); hutools的工具类
        return JSON.parseArray(s, ProductVo.class);
    }

    @SneakyThrows
    @Override
    public void registerDevice(DeviceDto deviceDto) {

        String iotId;
        try {
            //1.添加设备数据到Iot平台
            RegisterDeviceRequest request = deviceDto.getRegisterDeviceRequest();
            request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
            RegisterDeviceResponse response = client.registerDevice(request);
            if (!response.getBody().success) {
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }
            iotId = response.body.data.iotId;
            if (StrUtil.isBlank(iotId)) {
                throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
            }
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //2.添加设备数据到数据库
        try {
            Device device = BeanUtil.toBean(deviceDto, Device.class);
            device.setIotId(iotId);

            if (device.getLocationType() == 0) {
                device.setPhysicalLocationType(-1);//-1老人
            }
            deviceMapper.insert(device);
        } catch (Exception e) {
            //3.如果添加设备数据到数据库报错,删除Iot平台的设备数据
            DeleteDeviceRequest deviceRequest = new DeleteDeviceRequest();
            deviceRequest.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
            deviceRequest.setIotId(iotId);
            client.deleteDevice(deviceRequest);
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_DATE_ERROR);
        }
    }

    @Override
    public PageBean<DeviceVo> PagequeryDevice(DevicePageQueryDto dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        Page<DeviceVo> deviceVos = deviceMapper.selectPage(dto);
        return PageBean.of(deviceVos, DeviceVo.class);
    }

    @SneakyThrows
    @Override
    public DeviceVo QueryDeviceDetail(DeviceDto dto) {
        QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        request.setIotId(dto.getIotId());
        QueryDeviceDetailResponse response = client.queryDeviceDetail(request);

        DeviceVo deviceVo = deviceMapper.selectByIotId(dto.getIotId());
        BeanUtil.copyProperties(response.body.data, deviceVo);
        //BeanUtil.copyProperties区别
        // BeanUtil.toBean都可以拷贝对象但是拷贝对象时，toBean会忽略空值，copyProperties不会忽略空值,
        //toBean会创建一个对象,copyProperties不会创建一个新对象
        return deviceVo;
    }

    @SneakyThrows
    @Override
    public DevicePropertyStatusVo QueryDevicePropertyStatus(DeviceDto dto) {

        QueryDevicePropertyStatusRequest request = new QueryDevicePropertyStatusRequest();
        BeanUtil.copyProperties(dto, request);
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());

        QueryDevicePropertyStatusResponse response = client.queryDevicePropertyStatus(request);

        if (!response.getBody().success) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        DevicePropertyStatusVo vo = BeanUtil.toBean(response.body.data, DevicePropertyStatusVo.class);

        vo.getList().getPropertyStatusInfo().sort((o1, o2) -> StrUtil.equals("HeartRate", o1.getIdentifier()) ? -1 : 1);
        return vo;
    }

    @SneakyThrows
    @Override
    @Transactional
    public void UpdateDevice(DeviceDto dto) {
        //更新数据库中设备信息
        try {
            //将dto转换为pojo
            Device device = BeanUtil.toBean(dto, Device.class);
            //判断位置类型：0随身设备，1固定设备        如果是随身设备，将物理位置设为-1
            if (NumberUtil.equals(device.getLocationType(), 0)) {
                device.setPhysicalLocationType(-1);//物理位置类型 0楼层 1房间 2床位 -1随身设备
            }
            deviceMapper.updateByPrimaryKeySelective(device);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

        BatchUpdateDeviceNicknameResponse response;
        try {
            BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
            request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
            BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo
                    deviceNicknameInfo = new BatchUpdateDeviceNicknameRequest.
                    BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();

            deviceNicknameInfo.setIotId(dto.getIotId());
            deviceNicknameInfo.setNickname(dto.getNickname());

            request.setDeviceNicknameInfo(List.of(deviceNicknameInfo));
            response = client.batchUpdateDeviceNickname(request);

            if (!response.getBody().success) {
                throw new BaseException(BasicEnum.IOT_UPDATE_DEVICE_ERROR);
            }
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }
    }

    @SneakyThrows
    @Override
    @Transactional
    public void deleteDevice(DeviceDto dto) {
        /*删除数据库数据*/
        deviceMapper.deleteByIotId(dto.getIotId());
        /*删除阿里云平台数据*/
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        request.setIotId(dto.getIotId());
        client.deleteDevice(request);
    }

    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByWeek(QueryDeviceDataDto dto) {
        dto.setStartDate(LocalDateTimeUtil.of(dto.getStartTime()));
        dto.setEndDate(LocalDateTimeUtil.of(dto.getEndTime()));
        return deviceDataMapper.queryDeviceDataListByDay(dto);
    }

    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByDay(QueryDeviceDataDto dto) {
        dto.setStartDate(LocalDateTimeUtil.of(dto.getStartTime()));
        dto.setEndDate(LocalDateTimeUtil.of(dto.getEndTime()));
        return deviceDataMapper.queryDeviceDataListByWeek(dto);
    }

    @SneakyThrows
    @Override
    public QueryThingModelVo QueryThingModelPublished(DeviceDto dto) {
        QueryThingModelPublishedRequest request = new QueryThingModelPublishedRequest();
        request.setProductKey(dto.getProductKey());
        request.setIotInstanceId(aliyunIotProperties.getIotInstanceId());
        QueryThingModelVo bean = BeanUtil.toBean(client.queryThingModelPublished(request).body.data, QueryThingModelVo.class);
        return bean;
    }
}
